#!/usr/bin/env python

import logging

log = logging.getLogger('notify')
log.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
log.addHandler(ch)


import threading
import os
import sys
import tempfile
import SocketServer
import xml.dom.minidom
import configmanager
import struct
import socket
import pwd

from lxml import etree
from lxml import objectify
from configmanager import configManager

from Queue import Queue
from threading import Thread



def initParser(schemaFile):
  if not os.path.exists(schemaFile):
      log.error("Could not find schema for messages. There should be a "
                "file named '"+schemaFile+"' in the script directory")
      sys.exit(1)
  messageSchema = etree.XMLSchema(file=open(schemaFile, "r"))
  return objectify.makeparser(schema = messageSchema)

messageParser = initParser("resources/irc2you_message.xsd")
messageParserChannel = initParser("resources/irc2you_message_channel.xsd")

channelList = initParser("resources/irc2you_channelList.xsd")
getNick = initParser("resources/irc2you_getNick.xsd")
listofSockets =  []



class MyHandler(SocketServer.StreamRequestHandler):
  
    def finish(self):
        log.debug("closing socket")
        SocketServer.StreamRequestHandler.finish(self)
        log.debug("socket closed")

    def handle(self):
        while(True):
            log.debug("waiting for message")
            messageXML = self.rfile.readline()
            if(messageXML == ''):
                break
            log.debug("Message: " + messageXML)

            # Find username from unix socket
            pid, uid, gid = struct.unpack('3i', \
                    self.request.getsockopt(socket.SOL_SOCKET, 17, \
                    struct.calcsize('3i')))
            username = pwd.getpwuid(uid).pw_name

            #log.debug("client: " + str(self.server.socket))
            log.debug("pid: " + str(pid) + " uid: " + str(uid) + " gid: " + str(gid))
            log.debug(pwd.getpwuid(uid))

            try:
                message = objectify.fromstring(messageXML, messageParser)
                
                conf = configManager.getConfig(username)
                log.info("listans lengd" + str(len(message.context.item)))
                channel=message.channel.text
                log.info("channel"+message.channel.text)
                log.info("nummer 0:"+message.context.item[0].text)
                if len(message.context.item) >1 :
                    log.info("nummer 1:"+message.context.item[1].text)
                    log.info("nummer len-1:"+message.context.item[len(message.context.item)-1].text)
              
                idNummber=message.context.item[0].text.rpartition(":")[2].rsplit(" ")[0]
                log.info("numret vi soker: "+idNummber)
                log.info("----------------|"+message.channel+"|||"+message.sender+"|")
                if message.channel == message.sender:
                   log.info("righ channel")
                   if "yes" == str(message.message): 
                      log.info("shood add nummer i config")
                      confPath = os.path.expanduser("~"+username)+'/.irssi/irc2you_config.xml'
                      log.info('confpath:'+confPath)
                      confFile = open(confPath,"r")
                      
                      confString=""
                      while confFile:
                        row= str(confFile.readline())
                        confString += row
                        log.debug(row)
                        s = row.split()
                        n = len(s)
                        if n == 0:
                            break
                      confFile.close()
                      confFilewrite = open(confPath,"w")
                      if confString.find("<param name=\"id\">")!= -1 :
                          log.info("har redan en tel koplad till sig")
                      else :
                          log.info("har inte en tel koplad till sig")
                          SplitString=confString.rpartition("<engine type=\"android\">")
                          newfileString=SplitString[0]+SplitString[1]+"\n      <param name=\"andriod-id\">"+idNummber+"</param>"+SplitString[2]
                          log.info(newfileString)
                          confFilewrite.write(newfileString)
                          #write to file
                #for n in message.context.item:
                      confFilewrite.close()
                if conf:
                    for n in conf.notifiers:
                        log.debug("Executing notifier")
                        n.execute(message)
            except etree.XMLSyntaxError as element:
                try:
                    log.debug("faild to parse as hiligth trying channel")
                    channel = objectify.fromstring(messageXML, messageParserChannel)
                    log.debug(channel.returnport)
                    for conection in listofSockets:
                       if str(channel.returnport) in conection:
                           listofSockets.pop()
                           returnString="<channel><name>"+channel.channelName+"</name><rows>"
                           if hasattr(channel,'rows'):
                               for arow in channel.rows:
                                   #conection[channel.returnport].send(channel.rows.from)
                                   returnString +="<arow><msg>"+str(arow.msg)+"</msg>"
                                   returnString +="<name>"+str(arow.fromUser)+"</name>"
                                   returnString +="<timestamp>"+str(arow.timestamp)+"</timestamp></arow>"
                           returnString +="</rows></channel>"
                           log.debug("sending to andriodclienten:"+returnString)
                           conection[str(channel.returnport)].send(returnString);  
                           conection[str(channel.returnport)].close();
                           log.debug("is in the list returng list")
                except etree.XMLSyntaxError as element:
                    try:
                        log.debug("faild to parse as hiligth AND channel get channelList")
                        log.debug("len av listan:"+str(len(listofSockets)))
                        removeInt=0
                        channel = objectify.fromstring(messageXML, channelList)
                        for conection in  listofSockets:
                           if str(channel.returnport) in conection:
                               listofSockets.pop()
                               
                               returnString="<channelList>"
                               if hasattr(channel,'achannel'):
                                  for arow in channel.achannel:
                                       returnString+="<channel>"+arow+"</channel>"
                               returnString+="</channelList>"        
                               log.debug("sending to andriod: "+returnString)
                               log.debug(str(conection.keys())+" vs "+ channel.returnport)
                               con = conection[str(channel.returnport)]
                               con.send(returnString)
                               con.close()
                       
                    except etree.XMLSyntaxError as element:
                        try:
                            log.debug("faild to parse as hiligth AND channel AND channelList now on get nick")
                            log.debug("len av listan:"+str(len(listofSockets)))
                            removeInt=0
                            channel = objectify.fromstring(messageXML, getNick)
                            for conection in  listofSockets:
                               if str(channel.returnport) in conection:
                                   listofSockets.pop()
                                   
                                   returnString="<nick>"
                                   if hasattr(channel,'nick'):
                                       returnString+= channel.nick
                                   returnString+="</nick>"
                                   log.debug(returnString)
                                   log.debug(str(conection.keys())+" vs "+ channel.returnport)
                                   con = conection[str(channel.returnport)]
                                   con.send(returnString)
                                   con.close()
                           
                        except etree.XMLSyntaxError as element:
                            log.warn("Failed to parse message. Message: " + element.msg + \
                             ", XML: " + messageXML)
                            log.debug("=====  This line has been intentionally left brlank =====\n")

    def setup(self):
        log.debug("setting up socket")
        SocketServer.StreamRequestHandler.setup(self)
        self.messageQueue = Queue()
        t = Thread(target=self.message_sender)
        t.daemon = True
        t.start()
        pid, uid, gid = struct.unpack('3i', \
                self.request.getsockopt(socket.SOL_SOCKET, 17, \
                struct.calcsize('3i')))
        log.debug("uid till persson:" + str(uid));
        username = pwd.getpwuid(uid).pw_name
        conf = configManager.getConfig(username)
        conf.messageQueue = self.messageQueue
        log.debug("done setting up socket")

    def message_sender(self):
      while True:
        try:
            log.debug("[server->client] Waiting for message")
            item = self.messageQueue.get()
            log.debug("[server->client] Got message " + str(item))
            # Todo: Determine format of item
            # Todo: validation of item
            log.debug("order:"+item['order'] +"|");
            if item['order'] in "send" :
                row="<send><order>send</order><channel>"+item['channel']+"</channel><message>"+item['message']+"</message></send>\n"
                log.debug("send: "+row)
                self.wfile.write(row)
            elif item['order'] in "getchanel" :
                listofSockets.append(dict({str(item['port']):item['conection']}))
                row = "<send><order>getchanel</order><returnport>" + str(item['port']) + "</returnport><channel>" + str(item['channel']) + "</channel></send>\n";
                log.debug("sending getchanel:"+row)
                self.wfile.write(row)
            elif item['order'] in "getChanelList" :
                log.debug("getChanelList +")
                log.debug(str(item['port'])+" ")
                listofSockets.append(dict({str(item['port']):item['conection']}))
                row = "<send><order>getchanelList</order><returnport>" + str(item['port']) + "</returnport></send>\n"
                log.debug("row :"+row)
                self.wfile.write(row)
            elif item['order'] in "getNick" :
                log.debug("getNick +")
                log.debug(str(item['port'])+" ")
                listofSockets.append(dict({str(item['port']):item['conection']}))
                row = "<send><order>getNick</order><returnport>" + str(item['port']) + "</returnport></send>\n"
                log.debug("row :"+row)
                self.wfile.write(row)
            else :
                log.debug("can not read line irc2you-server row ")
            log.debug("-----------------------")    
            self.messageQueue.task_done()
        except Exception as e:
            print e

def main(*args):
    class ThreadingUnixStreamServer(SocketServer.ThreadingMixIn, \
            SocketServer.UnixStreamServer): pass
    log.debug("starting server")
    # Set named socket path and delete old socket, if any
    namedsocket = os.path.join(tempfile.gettempdir(), 'irc2you_socket')
    if(os.path.exists(namedsocket)):
        os.remove(namedsocket)
    #server = SocketServer.UnixStreamServer(namedsocket, MyHandler)
    server = ThreadingUnixStreamServer(namedsocket, MyHandler)
    os.chmod(namedsocket, 0777)
    
    log.debug("Starting server...")
    server.serve_forever()

    return 0

if __name__ == '__main__':
    sys.exit(main(*sys.argv))



